/*
 * author: VDaras
 */

#ifndef _RENDERINGMANAGER_H
#define	_RENDERINGMANAGER_H

#include "sdl/Screen.h"
#include "sdl/Canvas.h"
#include "sdl/Font.h"
#include "RenderLayer.h"

#if defined(_MSC_VER)
#include <memory>
#else
#include <auto_ptr.h>
#endif

#include <map>
#include <vector>

namespace Math
{
typedef Vector2Templ<float> Vector2F;
};

class ScriptRegister;

using namespace Math;

enum Direction //used by insertion algorithm
{
    LEFT, RIGHT
};

/**
 * Class handling rendering. When we want a drawable to be rendered, we register
 * the drawable to the rendering manager giving the name of the layer that we want
 * it to be drawn on. A map is used to hash Layers to their name. In order to achieve
 * prioritized rendering, a vector containing pointers to the same heap objects as the map is used.
 */
class RenderingManager
{
private:
    sdl::Canvas *m_screen;
    Camera *m_camera;
    std::map<std::string, RenderLayer *> m_layers;
    std::vector<RenderLayer *> m_sortedLayers;
    sdl::Font* debugFont;

public:

    RenderingManager();

    ~RenderingManager();

    void Init(sdl::Canvas *screen, Camera *camera);

    /**
     * Adds a new layer to the Rendering Manager.
     * @param name The name of the layer.
     * @param parallaxFactor
     */
    void AddLayer(const std::string& name, float parallaxFactor = 1);

    /**
     * Removes the selected layer. Drawables are not released.
     * @param name
     * @return 
     */
    bool RemoveLayer(const std::string& name);

    /**
     * Returns true if specified layer exists.
     * @param name
     * @return 
     */
    bool LayerExists(const std::string& name);

    bool BringToFront(const std::string& layerName);
    bool SendToBack(const std::string& layerName);
    bool BringForward(const std::string& layerName, unsigned int positions = 1);
    bool SendBackward(const std::string& layerName, unsigned int positions = 1);

    bool SetLayerVisiblity(const std::string& layerName, bool isVisible);
    void SetAllLayerVisibility(bool isVisible);

    bool RegisterDrawable(Drawable *toRegister, const std::string& layerName);
    bool UnregisterDrawable(Drawable *toUnrergister);

    /**
     * Searches for the layer that a drawable is registered to. If there is not
     * such layer returns NULL.
     *
     * @param toLocate - pointer to the Drawable to be located.
     * @return
     */
    RenderLayer *LocateDrawable(const Drawable *toLocate) const;

    void RenderLayers(sdl::GraphicsCore* gCore) const;

    void EraseAll();

    void Update();

    int LayerCount() const;


    /**
     * Renders a line on the screen.
     *
     * @param start - start of the line
     * @param end - end of the line
     * @param r
     * @param g
     * @param b
     */

    void RenderLine(const Vector2F& start, const Vector2F& end, int r, int g, int b);


    /**
     * Renders a rectangle on the screen
     *
     * @param origin - origin point of the rectangle
     * @param width - width of the rectangle
     * @param height - height of the rectangle
     */

    void RenderRect(const Vector2F& origin, int width, int height, int r, int g, int b);

    
    /**
     * Returns a pointer to the render's camera.
     */
    
    Camera* GetCamera();
    
    /**
     * Basic methods to print a single line debugging text.
     * @param origin - the origin of the line.
     * @param text - the text to print
     * @param color - the color of the text. If not specified text will be white.
     */
    void RenderText(const Vector2F& origin, const std::string& text, const sdl::Color& color);
    void RenderText(const Vector2F& origin, const std::string& text);

private:
    RenderLayer *FindLayer(const std::string& name);

    int LayerIndex(RenderLayer *test);

    void Insertion(int movingIndex, unsigned int positions, Direction dir);
};

#endif	/* _RENDERINGMANAGER_H */

